home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tde210.zip / DIRLIST.C < prev    next >
C/C++ Source or Header  |  1992-11-13  |  28KB  |  852 lines

  1. /*
  2.  * I wrote this function because I'm so stupid, I constantly forget
  3.  * file names and directory stuff.  The main function prompts for a
  4.  * subdirectory name or a search path.  The default search path is the
  5.  * cwd (current working directory).  In addition to being stupid, I'm also
  6.  * lazy.  If the user types a subdirectory name, I think we can assume he
  7.  * wants to list all files w/o having to type *.*   Let's save the cwd on
  8.  * whatever drive the user wishes to search, so we can restore it we get
  9.  * thru dir'ing.  Use the standard DOS functions to get and set directories.
  10.  *
  11.  *  The search pattern can contain wild card chars, valid file names, or
  12.  *  a valid subdirectory name.
  13.  *
  14.  * New editor name:  TDE, the Thomson-Davis Editor.
  15.  * Author:           Frank Davis
  16.  * Date:             June 5, 1991, version 1.0
  17.  * Date:             July 29, 1991, version 1.1
  18.  * Date:             October 5, 1991, version 1.2
  19.  * Date:             January 20, 1992, version 1.3
  20.  * Date:             February 17, 1992, version 1.4
  21.  * Date:             April 1, 1992, version 1.5
  22.  * Date:             June 5, 1992, version 2.0
  23.  * Date:             October 31, 1992, version 2.1
  24.  *
  25.  * This code is released into the public domain, Frank Davis.
  26.  *    You may distribute it freely.
  27.  */
  28.  
  29. #include "tdestr.h"
  30. #include "common.h"
  31. #include "define.h"
  32. #include "tdefunc.h"
  33. #include <malloc.h>
  34.  
  35.  
  36. /*
  37.  * Name:    dir_help
  38.  * Purpose: To prompt the user and list the directory contents
  39.  * Date:    February 13, 1992
  40.  * Passed:  window:  pointer to current window
  41.  */
  42. int  dir_help( WINDOW *window )
  43. {
  44. char dname[MAX_COLS+2]; /* directory search pattern */
  45. char stem[MAX_COLS+2];  /* directory stem */
  46. int rc;
  47.  
  48.    un_copy_line( window->cursor, window, TRUE );
  49.    dname[0] = '\0';
  50.    /*
  51.     * search path or pattern
  52.     */
  53.    if (get_name( dir1,
  54.                  window->bottom_line, dname, g_display.message_color ) == OK) {
  55.       if (validate_path( dname, stem ) == OK) {
  56.          rc = list_and_pick( dname, stem, window );
  57.  
  58.          /*
  59.           * if everything is everything, load in the file selected by user.
  60.           */
  61.          if (rc == OK)
  62.             attempt_edit_display( dname, LOCAL );
  63.       } else
  64.          /*
  65.           * invalid path or file name
  66.           */
  67.          error( WARNING, window->bottom_line, dir2 );
  68.    }
  69.    return( OK );
  70. }
  71.  
  72.  
  73. /*
  74.  * Name:    validate_path
  75.  * Purpose: make sure we got a valid search pattern or subdirectory
  76.  * Date:    February 13, 1992
  77.  * Passed:  dname: search path entered by user
  78.  *          stem:  directory stem is returned
  79.  * Returns: successful or not
  80.  * Notes:   we need to validate the search path or pattern.  if the search
  81.  *            pattern is valid, then we need to get the search stem.
  82.  *          the user may enter a subdirectory or some kind of search pattern.
  83.  *             if the user enters a subdirectory, then there are a few things
  84.  *             we need to take care of  1) find out if the subdirectory is
  85.  *             the root, 2) append a '\' to the subdirectory so we can create
  86.  *             a search pattern for the subdirectory, 3) don't append '\' to
  87.  *             the root, it already has a '\'.
  88.  *          if the user enters a search pattern, then we need to dissect the
  89.  *             search path.  we must create a stem from the search pattern.
  90.  */
  91. int  validate_path( char *dname, char *stem )
  92. {
  93. int rc;
  94. DTA dta;                /* temp disk transfer struct for findfirst, etc. */
  95. int fattr;
  96. int i;
  97. int len;
  98. char *p;
  99. char temp[MAX_COLS+2];  /* directory stem */
  100.  
  101.    /*
  102.     * if path name is void then the current working directory is implied.
  103.     */
  104.    if (dname[0] == '\0') {
  105.       strcpy( dname, stardotstar );
  106.       stem[0] = '\0';
  107.       rc = OK;
  108.    } else {
  109.  
  110.       /*
  111.        * get the attributes of the search pattern, so we can determine if
  112.        * this is a pattern or subdirectory.
  113.        */
  114.       rc = get_fattr( dname, &fattr );
  115.  
  116.       if (rc == OK && (fattr & SUBDIRECTORY)) {
  117.          strcpy( stem, dname );
  118.  
  119.          /*
  120.           * if this is the root directory ( \ ), don't append '\' to it.
  121.           * user entered a subdirectory - append *.* to get contents of
  122.           * subdirectory.
  123.           */
  124.          len = strlen( stem );
  125.          if (stem[len-1] != '\\') {
  126.             strcat( stem, "\\" );
  127.             strcat( dname, "\\" );
  128.          }
  129.          strcat( dname, stardotstar );
  130.  
  131.       /*
  132.        * not a subdirectory.  let's see if any files match the search
  133.        * pattern.
  134.        */
  135.       } else if (rc != ERROR) {
  136.          if ((rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  137.                               SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) {
  138.  
  139.             /*
  140.              * copy dname to "temp" so we can use "temp" to find the stem.
  141.              *    we need to search the pattern backwards to figure the stem.
  142.              */
  143.             strcpy( temp, dname );
  144.             len = strlen( dname );
  145.             for (i=len,p=temp+len; i>=0; i--) {
  146.                /*
  147.                 *  if we run into the '\' or the ':', then we got a stem.
  148.                 */
  149.                if (*p == '\\' || *p == ':') {
  150.                   p = temp + i;
  151.                   *(p+1) = '\0';
  152.                   break;
  153.                /*
  154.                 * if we're at the beginning of the string, stem == '\0'
  155.                 */
  156.                } else if (i == 0) {
  157.                   *p = '\0';
  158.                   break;
  159.                }
  160.                --p;
  161.             }
  162.             strcpy( stem, temp );
  163.          } else
  164.             rc = ERROR;
  165.  
  166.       /*
  167.        * user did not enter a valid subdirectory name or search pattern.
  168.        */
  169.       } else
  170.          rc = ERROR;
  171.    }
  172.    return( rc );
  173. }
  174.  
  175.  
  176. /*
  177.  * Name:    list_and_pick
  178.  * Purpose: To show matching file names and let user pick a file
  179.  * Date:    February 13, 1992
  180.  * Passed:  dname:  directory search pattern
  181.  *          stem:   stem of directory search pattern
  182.  *          window:  pointer to current window
  183.  * Returns: return code from pick.  rc = OK, then edit a new file.
  184.  * Notes:   real work routine of this function.  save the cwd and let the
  185.  *          user search upwards or downwards thru the directory structure.
  186.  *          since we are doing DOS directory functions, we need to check the
  187.  *            return code after each DOS call for critical errors.
  188.  */
  189. int  list_and_pick( char *dname, char *stem, WINDOW *window )
  190. {
  191. int rc;
  192. DTA dta;                /* disk transfer address for findfirst */
  193. DIRECTORY dir;          /* contains all info for dir display */
  194. unsigned int cnt;       /* number of matching files */
  195. FTYPE *flist, *p;       /* pointer to list of matching files */
  196. char cwd[MAX_COLS];     /* save the current working directory in this buff */
  197. char dbuff[MAX_COLS];   /* temporary directory buff */
  198. char prefix[MAX_COLS];  /* directory prefix  */
  199. int change_directory = FALSE;
  200. int stop;
  201. int len;
  202. int drive;
  203.  
  204.    /*
  205.     * Some algorithms alloc the maximum possible number of files in
  206.     *  a directory, eg. 256 or 512.  Let's count the number of matching
  207.     *  files so we know egxactly how much memory to request from calloc.
  208.     *  Depending on the op system, disk media, disk format, or version of DOS,
  209.     *  the max number of files may vary, anyway, also, additionally.
  210.     */
  211.    rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  212.                                 SUBDIRECTORY | ARCHIVE );
  213.    if (rc != ERROR) {
  214.       for (cnt=1; (rc = findnext( &dta )) == OK;)
  215.          ++cnt;
  216.       flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  217.    }
  218.    if (rc != ERROR && flist != NULL) {
  219.  
  220.       stop = FALSE;
  221.       /*
  222.        * If user entered drive name in search pattern, find out the drive and
  223.        *   directory stem.
  224.        */
  225.       if (stem[1] == ':') {
  226.  
  227.          /*
  228.           * If the second character of the search pattern is a ':', the
  229.           *   the first character of the pattern should be the drive.
  230.           *   Convert drive to lower case and get a numerical representation.
  231.           * CAVEAT:  In DOS v 2.x, there may be up to 63 logical drives.
  232.           *    this algorithm may blow up if the number of logical drives
  233.           *    is greater than 'Z'.
  234.           * For DOS >= 3, the number of drives is limited to 26, I think.
  235.           */
  236.          drive = stem[0];
  237.          if (drive < 'a')
  238.             drive += 32;
  239.          drive = drive - 'a' + 1;
  240.          rc = get_current_directory( dbuff, drive );
  241.          if (rc == ERROR)
  242.             stop = TRUE;
  243.          else {
  244.  
  245.             /*
  246.              * Put drive letter, ':', and '\' in front of current directory.
  247.              */
  248.             prefix[0] = (char)(drive - 1 + 'a');
  249.             prefix[1] = ':';
  250.             prefix[2] = '\\';
  251.             prefix[3] = '\0';
  252.             strcpy( cwd, prefix );
  253.             strcat( cwd, dbuff );
  254.          }
  255.  
  256.       /*
  257.        * else get current directory from default drive
  258.        */
  259.       } else {
  260.  
  261.          /*
  262.           * 0 = default drive.
  263.           */
  264.          drive = 0;
  265.          rc = get_current_directory( dbuff, drive );
  266.          if (rc == ERROR)
  267.             stop = TRUE;
  268.          else {
  269.  
  270.             /*
  271.              * Put a '\' in front of the current directory.
  272.              */
  273.             prefix[0] = '\\';
  274.             prefix[1] = '\0';
  275.             strcpy( cwd, prefix );
  276.             strcat( cwd, dbuff );
  277.          }
  278.       }
  279.  
  280.       save_screen( );
  281.       while (stop == FALSE) {
  282.          /*
  283.           * If we had enough memory, find all matching file names.  Append
  284.           *   '\\' at the end of subdirectory names so user will know if
  285.           *    name is a directory.  Might as well find everything, because
  286.           *    i also forget subdirectory names, too.
  287.           *
  288.           * when we get here, we have already done: 1) findfirst and findnext,
  289.           *   2) counted the number of matching files, and 3) allocated space.
  290.           */
  291.          p = flist;
  292.          cnt = 0;
  293.  
  294.          rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  295.                                  SUBDIRECTORY | ARCHIVE );
  296.          if (rc != ERROR) {
  297.  
  298.             /*
  299.              * p is pointer that walks down the file info structure.
  300.              *  save the file name, file size, and directory character,
  301.              *  if needed, for each matching file we find.
  302.              */
  303.             strcpy( p->fname, dta.name );
  304.             p->fsize = dta.size;
  305.             if (dta.attrib & SUBDIRECTORY)
  306.                strcat( p->fname, "\\" );
  307.             for (cnt=1; (rc = findnext( &dta )) == OK; ) {
  308.                ++p;
  309.                strcpy( p->fname, dta.name );
  310.                p->fsize = dta.size;
  311.                if (dta.attrib & SUBDIRECTORY)
  312.                   strcat( p->fname, "\\" );
  313.                cnt++;
  314.             }
  315.          }
  316.  
  317.          if (rc != ERROR) {
  318.             shell_sort( flist, cnt );
  319.  
  320.             /*
  321.              * figure out number of rows, cols, etc... then display dir list
  322.              */
  323.             setup_directory_window( &dir, cnt );
  324.             write_directory_list( flist, dir );
  325.  
  326.             /*
  327.              * Let user select file name or another search directory.
  328.              *  Save the choice in dbuff.  rc == OK if user selected file or dir.
  329.              */
  330.             rc = select_file( flist, stem, &dir );
  331.             strcpy( dbuff, flist[dir.select].fname );
  332.          }
  333.  
  334.          /*
  335.           *  give memory back.
  336.           */
  337.          free( flist );
  338.  
  339.          if (rc == ERROR)
  340.             stop = TRUE;
  341.          else {
  342.             len = strlen( dbuff );
  343.  
  344.             /*
  345.              * If the last character in a file name is '\' then let's
  346.              *   do a dir on selected directory.  See the matching
  347.              *   else when the user selects a file.
  348.              */
  349.             if (dbuff[len-1] == '\\') {
  350.  
  351.                /*
  352.                 * Stem has subdirectory path.  dbuff has selected path.
  353.                 * Create a new dname with stem and dbuff.
  354.                 */
  355.                strcpy( dname, stem );
  356.                strcat( dname, dbuff );
  357.                len = strlen( dname );
  358.                strcpy( dbuff, dname );
  359.  
  360.                /*
  361.                 * The last character in dbuff is '\', because we append the
  362.                 *   '\' to every directory entry in the file list.  Replace
  363.                 *   it with a NULL char then we will have a valid path name.
  364.                 */
  365.                dbuff[len-1] = '\0';
  366.  
  367.                /*
  368.                 * now let's change to the selected subdirectory.
  369.                 */
  370.                rc = set_current_directory( dbuff );
  371.                if (rc == OK) {
  372.  
  373.                   /*
  374.                    * Every time we change directories, we need to get the
  375.                    *   current directory so we will be sure to have the
  376.                    *   correct path.
  377.                    */
  378.                   rc = get_current_directory( dbuff, drive );
  379.                   if (rc == OK) {
  380.                      strcpy( dname, prefix );
  381.                      strcat( dname, dbuff );
  382.                      change_directory = TRUE;
  383.                   }
  384.                }
  385.  
  386.                /*
  387.                 * Validate the new path and allocate memory for the
  388.                 *   matching files.
  389.                 */
  390.                if (rc == OK)
  391.                   rc = validate_path( dname, stem );
  392.                if (rc == OK) {
  393.                   rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  394.                                   SYSTEM | SUBDIRECTORY | ARCHIVE );
  395.                   if (rc != ERROR) {
  396.                      for (cnt=1; (rc = findnext( &dta )) == OK;)
  397.                         ++cnt;
  398.                      flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  399.                   }
  400.                }
  401.                if (flist == NULL || rc == ERROR) {
  402.                   stop = TRUE;
  403.                   rc = ERROR;
  404.                }
  405.             } else {
  406.  
  407.                /*
  408.                 *  user selected a file.  store fname in dname and return.
  409.                 */
  410.                rc = OK;
  411.                stop = TRUE;
  412.                strcpy( dname, stem );
  413.                strcat( dname, dbuff );
  414.             }
  415.          }
  416.       }
  417.  
  418.       /*
  419.        * Go back to the current directory if needed.
  420.        */
  421.       if (change_directory)
  422.          set_current_directory( cwd );
  423.       restore_screen( );
  424.    } else {
  425.       /*
  426.        * out of memory
  427.        */
  428.       error( WARNING, window->bottom_line, dir3 );
  429.       rc = ERROR;
  430.    }
  431.    return( rc );
  432. }
  433.  
  434.  
  435. /*
  436.  * Name:    setup_directory_window
  437.  * Purpose: set number of rows and cols in directory window
  438.  * Date:    February 13, 1992
  439.  * Passed:  dir: pointer to directory structure
  440.  *          cnt: number of files
  441.  * Notes:   set up stuff we need to know about how to display files.
  442.  */
  443. void setup_directory_window( DIRECTORY *dir, int cnt )
  444. {
  445. int i;
  446. int wid;
  447. char temp[MAX_COLS];       /* line to output */
  448.  
  449.    /*
  450.     * setup the fixed vars used in dir display.
  451.     *    dir->col =      physical upper left column of dir screen
  452.     *    dir->row =      physical upper left row or line of dir screen
  453.     *    dir->wid =      width of physical screen
  454.     *    dir->hgt =      height of physical screen
  455.     *    dir->max_cols   number of columns of files in dir screen
  456.     *    dir->max_lines  number of lines of files in each column in dir screen
  457.     *    dir->cnt        number of files in list
  458.     */
  459.    dir->col = 3;
  460.    dir->row = 5;
  461.    wid = dir->wid = 72;
  462.    dir->hgt = 16;
  463.    dir->max_cols = 5;
  464.    dir->max_lines = 9;
  465.    dir->cnt = cnt;
  466.  
  467.    /*
  468.     *  Find out how many lines in each column are needed to display
  469.     *     matching files.
  470.     */
  471.    dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
  472.    if (dir->lines > dir->max_lines)
  473.       dir->lines = dir->max_lines;
  474.  
  475.    /*
  476.     * Find out how many columns of file names we need.
  477.     */
  478.    dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
  479.    if (dir->cols > dir->max_cols)
  480.       dir->cols = dir->max_cols;
  481.  
  482.  
  483.    /*
  484.     * Find the maximun number of file names we can display in help screen.
  485.     */
  486.    dir->avail = dir->lines * dir->cols;
  487.  
  488.    /*
  489.     * Now find the number of file names we do have on the screen.  Every
  490.     *   time we slide the "window", we have to calculate a new nfiles.
  491.     */
  492.    dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
  493.  
  494.    /*
  495.     * A lot of times, the number of matching files will not fit evenly
  496.     *   in our help screen.  The last column on the right will be partially
  497.     *   filled, hence the variable name prow (partial row).  When there are
  498.     *   more file names than can fit on the screen, we have to calculate
  499.     *   prow every time we slide the "window" of files.
  500.     */
  501.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  502.  
  503.    /*
  504.     * Find out how many "virtual" columns of file names we have.  If
  505.     *   all the files can fit in the dir screen, there will be no
  506.     *   virtual columns.
  507.     */
  508.    if (dir->cnt < dir->avail)
  509.       dir->vcols = 0;
  510.    else
  511.       dir->vcols =  (dir->cnt - dir->avail) / dir->max_lines +
  512.                    ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
  513.  
  514.    /*
  515.     * Find the physical display column in dir screen.
  516.     */
  517.    dir->flist_col[0] = dir->col + 2;
  518.    for (i=1; i<dir->max_cols; i++)
  519.       dir->flist_col[i] = dir->flist_col[i-1] + 14;
  520.  
  521.    /*
  522.     * Now, draw the borders of the dir screen.
  523.     */
  524.    for (i=0; i < dir->hgt; i++) {
  525.       if (i == 0 || i == dir->hgt-1) {
  526.          memset( temp, '─', wid );
  527.          temp[wid] = '\0';
  528.          if (i == 0) {
  529.             temp[0] = '┌';
  530.             temp[wid-1] = '┐';
  531.          } else {
  532.             temp[0] = '└';
  533.             temp[wid-1] = '┘';
  534.          }
  535.       } else {
  536.          memset( temp, ' ', wid );
  537.          temp[wid] = '\0';
  538.          temp[0] = temp[wid-1] = '│';
  539.       }
  540.       s_output( temp, dir->row+i, dir->col, g_display.help_color );
  541.    }
  542.  
  543.    /*
  544.     * Write headings in help screen.
  545.     */
  546.    s_output( dir4, dir->row+1, dir->col+3, g_display.help_color );
  547.    s_output( dir5, dir->row+2, dir->col+3, g_display.help_color );
  548.    s_output( dir6, dir->row+2, dir->col+44, g_display.help_color );
  549.    s_output( dir7, dir->row+14, dir->col+8, g_display.help_color );
  550. }
  551.  
  552.  
  553. /*
  554.  * Name:    write_directory_list
  555.  * Purpose: given directory list, display matching files
  556.  * Date:    February 13, 1992
  557.  * Passed:  flist: pointer to list of files
  558.  *          dir:   directory display structure
  559.  * Notes:   blank out the previous file name and display the new one.
  560.  */
  561. void write_directory_list( FTYPE *flist, DIRECTORY dir )
  562. {
  563. FTYPE *p, *top;
  564. int i;
  565. int j;
  566. int k;
  567. int end;
  568. int line;
  569. int col;
  570. int color;
  571.  
  572.    color = g_display.help_color;
  573.    top = flist;
  574.    for (i=0; i < dir.lines; ++i) {
  575.       p = top;
  576.       end = FALSE;
  577.       for (j=0; j < dir.cols; ++j) {
  578.          col = dir.flist_col[j];
  579.          line = i + dir.row + 4;
  580.  
  581.          /*
  582.           * We need to blank out all lines and columns used to display
  583.           *   files, because there may be some residue from a previous dir
  584.           */
  585.          s_output( "            ", line, col, color );
  586.          if (!end) {
  587.             s_output( p->fname, line, col, color );
  588.             p += dir.lines;
  589.             k = p - flist;
  590.             if (k >= dir.nfiles)
  591.                end = TRUE;
  592.          }
  593.       }
  594.       ++top;
  595.    }
  596. }
  597.  
  598.  
  599. /*
  600.  * Name:    select_file
  601.  * Purpose: To let user select a file from dir list
  602.  * Date:    February 13, 1992
  603.  * Passed:  flist: pointer to list of files
  604.  *          stem:  base directory
  605.  *          dir:   directory display stuff
  606.  * Notes:   let user move thru the file names with the cursor keys
  607.  */
  608. int  select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
  609. {
  610. int ch;         /* input character from user */
  611. int func;       /* function of character input by user */
  612. int fno;        /* index into flist of the file under cursor */
  613. int goodkey;    /* is key a recognized function key? */
  614. int r;          /* current row of cursor */
  615. int c;          /* current column of cursor */
  616. int offset;     /* offset into file list */
  617. int stop;       /* stop indicator */
  618. int stem_len;   /* stem length */
  619. int color;      /* color of help screen */
  620. int file_color; /* color of current file */
  621. int change;     /* boolean, hilite another file? */
  622. int oldr;       /* old row */
  623. int oldc;       /* old column */
  624. char asize[20]; /* ascii file size */
  625. char blank[20]; /* blank out file names */
  626.  
  627.    /*
  628.     * initial everything.
  629.     */
  630.    memset( blank, ' ', 12 );
  631.    blank[12] = '\0';
  632.    c = r = 1;
  633.    ch = fno = offset = 0;
  634.    color = g_display.help_color;
  635.    file_color = g_display.hilited_file;
  636.    goodkey = TRUE;
  637.    stop = FALSE;
  638.    stem_len = strlen( stem );
  639.    s_output( stem, dir->row+1, dir->col+19, color );
  640.    s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  641.    ltoa( flist[fno].fsize, asize, 10 );
  642.    s_output( blank, dir->row+2, dir->col+19, color );
  643.    s_output( asize, dir->row+2, dir->col+19, color );
  644.    itoa( dir->cnt,  asize, 10 );
  645.    s_output( blank, dir->row+2, dir->col+57, color );
  646.    s_output( asize, dir->row+2, dir->col+57, color );
  647.    xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  648.    hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  649.    change = FALSE;
  650.    while (stop == FALSE) {
  651.       oldr = r;
  652.       oldc = c;
  653.       ch = getkey( );
  654.       func = getfunc( ch );
  655.  
  656.       /*
  657.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  658.        * perform a Rturn in this function. Make the ESC key do an AbortCommand.
  659.        */
  660.       if (ch == RTURN)
  661.          func = Rturn;
  662.       else if (ch == ESC)
  663.          func = AbortCommand;
  664.  
  665.       switch (func) {
  666.          case Rturn       :
  667.          case NextLine    :
  668.          case BegNextLine :
  669.             stop = TRUE;
  670.             break;
  671.          case AbortCommand :
  672.             stop = TRUE;
  673.             break;
  674.          case LineUp :
  675.             if (r > 1) {
  676.                change = TRUE;
  677.                --r;
  678.             } else {
  679.                r = dir->lines;
  680.                change = TRUE;
  681.                if (offset == 0 || c > 1) {
  682.                   if (c > 1)
  683.                      --c;
  684.                } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  685.                   /*
  686.                    * recalculate the dir display stuff.
  687.                    */
  688.                   offset -= dir->lines;
  689.                   recalculate_dir( dir, flist, offset );
  690.                }
  691.             }
  692.             goodkey = TRUE;
  693.             break;
  694.          case LineDown :
  695.             if (r < dir->prow) {
  696.                change = TRUE;
  697.                ++r;
  698.             } else if (r < dir->lines && c != dir->cols) {
  699.                change = TRUE;
  700.                ++r;
  701.             } else {
  702.                change = TRUE;
  703.                r = 1;
  704.                if (offset == dir->vcols * dir->lines || c < dir->cols) {
  705.                   if (c < dir->cols)
  706.                      ++c;
  707.                } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  708.                          c == dir->cols) {
  709.                   offset += dir->lines;
  710.                   recalculate_dir( dir, flist, offset );
  711.                }
  712.             }
  713.             goodkey = TRUE;
  714.             break;
  715.          case CharLeft :
  716.             if (offset == 0 || c > 1) {
  717.                if (c > 1) {
  718.                   change = TRUE;
  719.                   --c;
  720.                }
  721.             } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  722.                change = TRUE;
  723.  
  724.                /*
  725.                 * recalculate the dir display stuff.
  726.                 */
  727.                offset -= dir->lines;
  728.                recalculate_dir( dir, flist, offset );
  729.             }
  730.             goodkey = TRUE;
  731.             break;
  732.          case CharRight :
  733.             if (offset == dir->vcols * dir->lines || c < dir->cols) {
  734.                if (c < dir->cols) {
  735.                   change = TRUE;
  736.                   ++c;
  737.                   if (c == dir->cols) {
  738.                      if ( r > dir->prow)
  739.                         r = dir->prow;
  740.                   }
  741.                }
  742.             } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  743.                          c == dir->cols) {
  744.                change = TRUE;
  745.                offset += dir->lines;
  746.                recalculate_dir( dir, flist, offset );
  747.                if (r > dir->prow)
  748.                   r = dir->prow;
  749.             }
  750.             goodkey = TRUE;
  751.             break;
  752.          case BegOfLine :
  753.             change = TRUE;
  754.             c = r = 1;
  755.             goodkey = TRUE;
  756.             break;
  757.          case EndOfLine :
  758.             change = TRUE;
  759.             r = dir->prow;
  760.             c = dir->cols;
  761.             goodkey = TRUE;
  762.             break;
  763.          case ScreenDown :
  764.             change = TRUE;
  765.             r = (c == dir->cols) ? r = dir->prow : dir->lines;
  766.             goodkey = TRUE;
  767.             break;
  768.          case ScreenUp :
  769.             change = TRUE;
  770.             r = 1;
  771.             goodkey = TRUE;
  772.             break;
  773.       }
  774.       if (goodkey) {
  775.          s_output( blank, dir->row+1, dir->col+19+stem_len, color );
  776.          fno = offset + (c-1)*dir->lines + (r-1);
  777.          s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  778.          ltoa( flist[fno].fsize, asize, 10 );
  779.          s_output( blank, dir->row+2, dir->col+19, color );
  780.          s_output( asize, dir->row+2, dir->col+19, color );
  781.          xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  782.          goodkey = FALSE;
  783.          if (change) {
  784.             hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color );
  785.             hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  786.             change = FALSE;
  787.          }
  788.       }
  789.    }
  790.    dir->select = fno;
  791.    return( func == AbortCommand ? ERROR : OK );
  792. }
  793.  
  794.  
  795. /*
  796.  * Name:    recalculate_dir
  797.  * Purpose: To recalcute dir structure when cursor goes ahead or behind screen
  798.  * Date:    February 13, 1992
  799.  * Passed:  dir:    pointer to file structure
  800.  *          flist:  pointer to file structure
  801.  *          offset: number of files from beginning of flist
  802.  * Notes:   Find new number of files on the screen.  Then, find out
  803.  *          how many files names are in the last column.
  804.  */
  805. void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset )
  806. {
  807. register int off;
  808.  
  809.    off = offset;
  810.    dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail :
  811.                 (dir->cnt - off);
  812.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  813.    write_directory_list( flist+off, *dir );
  814. }
  815.  
  816.  
  817. /*
  818.  * Name:    shell_sort
  819.  * Purpose: To sort file names
  820.  * Date:    February 13, 1992
  821.  * Passed:  flist: pointer to file structure
  822.  *          cnt:   number of files to sort
  823.  */
  824. void shell_sort( FTYPE *flist, int cnt )
  825. {
  826. register int i;
  827. int inc;
  828. int limit;
  829. int change;
  830. FTYPE temp;
  831. FTYPE *fl;
  832.  
  833.    fl = flist;
  834.    inc = cnt / 2;
  835.    while (inc) {
  836.       limit = cnt - inc - 1;
  837.       do {
  838.          change = FALSE;
  839.          for (i=0; i<=limit; i++) {
  840.             if (memcmp( fl[i].fname, fl[i+inc].fname, 14 ) > 0) {
  841.                memcpy( &temp, fl+i, sizeof(FTYPE) );
  842.                memcpy( fl+i, fl+i+inc, sizeof(FTYPE) );
  843.                memcpy( fl+i+inc, &temp, sizeof(FTYPE) );
  844.                change = i;
  845.             }
  846.          }
  847.          limit = change - inc;
  848.       } while (change);
  849.       inc = inc / 2;
  850.    }
  851. }
  852.